package com.bkgy.controller.tPdiDataL3Tcm2280.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bkgy.commom.model.Temp;
import com.bkgy.controller.acidefficiency.dao.AcidEfficiencyDao;
import com.bkgy.controller.acidefficiency.entity.TbTcm22280ProSpeed;
import com.bkgy.controller.tPdiDataL3Tcm2280.entity.RepTcmOutputHour;
import com.bkgy.controller.tPdiDataL3Tcm2280.entity.TPdiDataL3Tcm2280;
import com.bkgy.controller.tPdiDataL3Tcm2280.entity.pdo.RepOutputReasonReq;
import com.bkgy.controller.tPdiDataL3Tcm2280.entity.pdo.RepOutputReasonRes;
import com.bkgy.controller.tPdiDataL3Tcm2280.mapper.IRepTcmOutputHourMapper;
import com.bkgy.controller.tPdiDataL3Tcm2280.service.IRepTcmOutputHourService;
import com.bkgy.controller.tPdiDataL3Tcm2280.service.ITPdiDataL3Tcm2280Service;
import com.bkgy.controller.tpdol3data.dao.TPdoL3Tcm2280Dao;
import com.bkgy.controller.tpdol3data.entity.OutputSec;
import com.bkgy.controller.tpdol3data.entity.TPdoDataL3Tcm2280;
import com.bkgy.jobs.outputL3Listener.ITcm2280L3Listener;
import com.bkgy.modular.tpdidata_cal1630.service.ITPdiDataMesService;
import com.bkgy.sys.common.entity.ResultData;
import com.bkgy.util.DateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class RepTcmOutputHourServiceImpl extends ServiceImpl<IRepTcmOutputHourMapper, RepTcmOutputHour>
        implements IRepTcmOutputHourService, ITcm2280L3Listener {
    private final IRepTcmOutputHourMapper mapper;
    private final TPdoL3Tcm2280Dao tcmPdoMapper;
    private final AcidEfficiencyDao acidEfficiencyDao;
    private final ITPdiDataMesService pdiMesService;
    private final ITPdiDataL3Tcm2280Service pdiTcm2280Service;

    @Override
    public ResultData<RepOutputReasonRes> selectOutputHourRep(String beginDate, String endDate) {
        LambdaQueryWrapper<RepTcmOutputHour> w = new LambdaQueryWrapper<>();
        w.ge(RepTcmOutputHour::getShijian, beginDate).le(RepTcmOutputHour::getShijian, endDate)
                .orderByDesc(RepTcmOutputHour::getShijian).orderByAsc(RepTcmOutputHour::getHour);
        List<RepTcmOutputHour> list = list(w);
        //按天分组
        Map<String, List<RepTcmOutputHour>> map = new HashMap<>();
        for (RepTcmOutputHour r : list) {
            if (!map.containsKey(r.getShijian())) {
                List<RepTcmOutputHour> l = new ArrayList<>();
                l.add(r);
                map.put(r.getShijian(), l);
            } else {
                map.get(r.getShijian()).add(r);
            }
        }

        List<RepOutputReasonRes> resList = new ArrayList<>();
        String[] typeArr = new String[]{"计划产量", "实际产量", "计划卷数", "实际卷数", "未达标理论原因", "实际原因(人工填写)"};
        for (Map.Entry<String, List<RepTcmOutputHour>> entry : map.entrySet()) {
            List<RepOutputReasonRes> tempList = new ArrayList<>();
            List<RepTcmOutputHour> dayList = entry.getValue();
            String[][] arr = new String[dayList.size()][6];
            for (int i = 0; i < dayList.size(); i++) {
                RepTcmOutputHour r = dayList.get(i);
                arr[i][0] = r.getOutMatWt1().toString();
                arr[i][1] = r.getOutMatWt2().toString();
                arr[i][2] = r.getTargetRoll() + "";
                arr[i][3] = r.getActualRoll() + "";
                arr[i][4] = r.getAutoReason();
                arr[i][5] = r.getReason();
            }
            //将内容进行行列转换
            String[][] resArr = new String[arr[0].length][dayList.size()];
            for (int i = 0; i < dayList.size(); i++) {
                for (int j = 0; j < arr[0].length; j++) {
                    resArr[j][i] = arr[i][j];
                }
            }
            //赋值新对象
            for (int i = 0; i < resArr.length; i++) {
                RepOutputReasonRes res = new RepOutputReasonRes();
                res.setShijian(entry.getKey());
                res.setType(typeArr[i]);

                for (int j = 0; j < resArr[i].length; j++) {
                    try {
                        res.getClass().getMethod("setH" + j, String.class).invoke(res, resArr[i][j]);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                tempList.add(res);
            }
            resList.addAll(tempList);
        }

        return ResultData.ResultDataSuccess(resList, resList.size());
    }

    @Override
    public boolean buildOutputBeforeHour(Date date) {
        //获取传入时间的前一个小时时间段
        String beginTime = DateUtil.getBeforeHourStart(date);
        Date d = DateUtil.getStringToDate("yyyyMMddHH", beginTime);
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        cal.add(Calendar.HOUR_OF_DAY, 1);
        String endTime = DateUtil.getDateToString(cal.getTime(), "yyyyMMddHH");

        //查询前一小时时间段的L3酸轧生产数据
        LambdaQueryWrapper<TPdoDataL3Tcm2280> wrapper = new LambdaQueryWrapper<>();
        wrapper.ge(TPdoDataL3Tcm2280::getProdEndTime, beginTime).lt(TPdoDataL3Tcm2280::getProdEndTime, endTime).orderByAsc(TPdoDataL3Tcm2280::getProdEndTime);
        List<TPdoDataL3Tcm2280> actualList = tcmPdoMapper.selectList(wrapper);
        log.info("{}--{}产量记录数：{}", beginTime, endTime, actualList.size());

        RepTcmOutputHour output = new RepTcmOutputHour();
        output.setHour(hour);
        output.setOutputType(1);
        output.setShijian(beginTime.substring(0, 8));

        //没有生产数据
        if (actualList == null || actualList.size() == 0) {
            Date d1 = tcmPdoMapper.selectTopOneRecord().getD();
            OutputSec sec = pdiMesService.sumOutputSecInfo(d1, 60 * 60);
            output.setFirstEntid(sec.getFirstEntid());
            output.setEndEntid(sec.getLastEntid());
            output.setOutputSe(sec.getTotalSec());
            output.setTargetRoll(sec.getTotalRoll());
            output.setOutMatWt1(sec.getTotalOutput());
            output.setActualRoll(0);
            output.setOutMatWt2(BigDecimal.ZERO);
        } else {
            //根据生产记录的入口卷号，查询计划数据
            TPdiDataL3Tcm2280 pidObj = null;
            BigDecimal outMatWt2 = BigDecimal.ZERO;
            for (TPdoDataL3Tcm2280 pdo : actualList) {
                String entId = pdo.getEntid();
                output.setBanzu(pdo.getCrew());
                outMatWt2 = outMatWt2.add(pdo.getOutMatWt());
                if (pidObj == null) {
                    pidObj = pdiTcm2280Service.selectByEntId(entId);
                }
            }
            if (pidObj != null) {
                //每次获取30条数据，累加够1小时的数据
                OutputSec sec = pdiMesService.sumOutputSecInfo(pidObj.getCreateTime(), 60 * 60);
                output.setFirstEntid(sec.getFirstEntid());
                output.setEndEntid(sec.getLastEntid());
                output.setOutputSe(sec.getTotalSec());
                output.setTargetRoll(sec.getTotalRoll());
                output.setOutMatWt1(sec.getTotalOutput());
                output.setActualRoll(actualList.size());
                output.setOutMatWt2(outMatWt2);

                //自动原因分析
                if (output.getActualRoll() < output.getTargetRoll()) {
                    StringBuffer sbf = new StringBuffer();
                    //分析发生重焊卷数
                    List<Integer> list = mapper.selectReweldTimes(d, cal.getTime());
                    if (list.size() > 0) {
                        sbf.append("重焊卷数：").append(list.size()).append("，最高重焊").append(list.get(0) - 1).append("次;");
                    }
                    //分析速度达成率
                    List<TbTcm22280ProSpeed> effList = acidEfficiencyDao.selectEff(beginTime, endTime);
                    int zeroCount = 0;
                    for (TbTcm22280ProSpeed p : effList) {
                        if (p.getS5exSpeedLimit().compareTo(BigDecimal.ZERO) == 0) {
                            if (p.getExSpeedMax().compareTo(p.getS5exSpeedL2Set().multiply(BigDecimal.valueOf(0.9))) < 0) {
                                zeroCount++;
                            }
                        } else {
                            //S5EX_SPEED_LIMIT 不是0时，EX_SPEED_MAX >= （ S5EX_SPEED_L2_SET | S5EX_SPEED_LIMIT 较小的*0.9）
                            BigDecimal jiaoxiao = p.getS5exSpeedL2Set().compareTo(p.getS5exSpeedLimit()) > 0 ? p.getS5exSpeedLimit() : p.getS5exSpeedL2Set();
                            if (p.getExSpeedMax().compareTo(jiaoxiao.multiply(BigDecimal.valueOf(0.9))) < 0) {
                                zeroCount++;
                            }
                        }
                    }
                    if (zeroCount > 0) {
                        sbf.append("重焊速度未达标数：").append(zeroCount).append(";");
                    }

                    output.setAutoReason(sbf.toString());
                }

            } else {
                //居然有的卷号不在秒用时计划中！！
                output.setOutputSe(0);
                output.setTargetRoll(0);
                output.setOutMatWt1(BigDecimal.ZERO);
                output.setActualRoll(actualList.size());
                output.setOutMatWt2(outMatWt2);
            }

        }
        save(output);

        return true;
    }

    @Override
    public void currentHourOutput() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        String shijian = DateUtil.getDateToString(calendar.getTime(), "yyyyMMdd");

        //当前小时实际产出数据
        BigDecimal sumActualOutput = BigDecimal.ZERO;
        List<Temp> actulList = tcmPdoMapper.selectCurrentHourOutput(DateUtil.getDateToString(calendar.getTime(), "yyyyMMddHH"));
        String crew = null;
        String entId = null;
        if (actulList.isEmpty()) {
            //当前没有生产卷，获取最新一条记录的时间
            Temp obj = tcmPdoMapper.selectTopOneRecord();
            entId = obj.getK();
        } else {
            for (int i = 0; i < actulList.size(); i++) {
                Temp temp = actulList.get(i);
                if (i == 0) {//时间段生产的最早一条记录
                    entId = temp.getK1();
                }
                sumActualOutput = sumActualOutput.add(temp.getV());
                crew = temp.getK();
            }
        }
        //查询时间内的最早卷对应的排产时间
        Temp temp = tcmPdoMapper.selectToc(entId);
        //基础时间点
        Date levelTime = temp.getD();

        //当前时间段是否已经有对应的记录
        LambdaQueryWrapper<RepTcmOutputHour> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RepTcmOutputHour::getShijian, shijian).eq(RepTcmOutputHour::getHour, hour);
        RepTcmOutputHour output = getOne(wrapper);
        boolean flag = true;//是否有记录
        if (output == null) {//时间段之初只构建一次
            flag = false;
            output = new RepTcmOutputHour();
            output.setShijian(shijian);
            output.setHour(hour);
            output.setOutputType(1);
            output.setBanzu(crew);
            OutputSec sec = pdiMesService.sumOutputSecInfo(levelTime, 60 * 60);
            output.setFirstEntid(sec.getFirstEntid());
            output.setEndEntid(sec.getLastEntid());
            output.setOutputSe(sec.getTotalSec());
            output.setTargetRoll(sec.getTotalRoll());
            output.setOutMatWt1(sec.getTotalOutput());
        }

        output.setActualRoll(actulList.size());
        output.setOutMatWt2(sumActualOutput);

        if (flag) {
            LambdaQueryWrapper<RepTcmOutputHour> w = new LambdaQueryWrapper<>();
            w.eq(RepTcmOutputHour::getShijian, shijian).eq(RepTcmOutputHour::getHour, hour);
            update(output, w);
        } else {
            save(output);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void buildOutput2HourJob() {
        Date now = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(now);
        cal.add(Calendar.HOUR_OF_DAY, -1);
        Date towHourBefore = cal.getTime();//过去的1小时时间
        String shijian1 = DateUtil.getDateToString(towHourBefore, "yyyyMMdd");
        int hour1 = cal.get(Calendar.HOUR_OF_DAY);
        cal.add(Calendar.HOUR_OF_DAY, -1);
        Date d1 = cal.getTime();//过去的2小时时间
        String shijian2 = DateUtil.getDateToString(d1, "yyyyMMdd");
        int hour2 = cal.get(Calendar.HOUR_OF_DAY);

        //删掉上两个小时段数据，处理延迟问题
        LambdaQueryWrapper<RepTcmOutputHour> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RepTcmOutputHour::getShijian, shijian1).eq(RepTcmOutputHour::getHour, hour1).or().eq(RepTcmOutputHour::getShijian, shijian2).eq(RepTcmOutputHour::getHour, hour2);
        remove(wrapper);

        //构建前2小时段数据
        buildOutputBeforeHour(towHourBefore);
        //构建前1个小时的数据
        boolean res2 = buildOutputBeforeHour(now);
        log.info(res2 ? "{}产量计划/实际数据构建完毕" : "【注意】：{}数据构建失败", DateUtil.getDateToString(new Date(), "MM/dd"));
    }

    @Override
    public boolean buildOutput2280Day() {
        //查询今日生产的最早时间
        Date current = new Date();
        String startTime = DateUtil.getDateToString(current, "yyyyMMdd");
        List<Temp> dayOutputList = tcmPdoMapper.selectDayOutput(startTime);
        //秒用时排到的最新时间点
        Date d = dayOutputList.isEmpty() ? tcmPdoMapper.selectTopOneRecord().getD() : dayOutputList.get(0).getD();

        RepTcmOutputHour output = new RepTcmOutputHour();
        //今日当前时间后剩余秒数
        long overSec = (current.getTime() - DateUtil.getStringToDate("yyyyMMdd", startTime).getTime()) / 1000;
        long leftSec = 60 * 60 * 24 - (overSec);
        OutputSec leftOutputSecsec = pdiMesService.sumOutputSecInfo(d, leftSec);

        output.setHour(0);
        output.setOutputType(1);
        output.setShijian("0");
        output.setActualRoll(0);
        output.setOutMatWt2(BigDecimal.ZERO);
        output.setFirstEntid(leftOutputSecsec.getFirstEntid());
        output.setEndEntid(leftOutputSecsec.getLastEntid());
        output.setOutputSe(leftOutputSecsec.getTotalSec());

        //查询今日实际产量
        BigDecimal sumActualOutput = BigDecimal.ZERO;
        LambdaQueryWrapper<TPdoDataL3Tcm2280> wrapper = new LambdaQueryWrapper<>();
        wrapper.ge(TPdoDataL3Tcm2280::getProdEndTime, startTime);
        List<TPdoDataL3Tcm2280> list = tcmPdoMapper.selectList(wrapper);
        for (TPdoDataL3Tcm2280 t : list) {
            sumActualOutput = sumActualOutput.add(t.getOutMatWt());
        }
        output.setTargetRoll(leftOutputSecsec.getTotalRoll() + list.size());
        output.setOutMatWt1(leftOutputSecsec.getTotalOutput().add(sumActualOutput));

        LambdaQueryWrapper<RepTcmOutputHour> w = new LambdaQueryWrapper<>();
        w.eq(RepTcmOutputHour::getShijian, "0");
        if (getOne(w) != null) {
            update(output, w);
        } else {
            save(output);
        }

        return true;
    }

    @Override
    public ResultData<String> updateReason(RepOutputReasonReq req) {
        RepTcmOutputHour obj = new RepTcmOutputHour();
        obj.setReason(req.getReason());
        LambdaQueryWrapper<RepTcmOutputHour> w = new LambdaQueryWrapper<>();
        w.eq(RepTcmOutputHour::getShijian, req.getShijian()).eq(RepTcmOutputHour::getHour, req.getHour());
        return ResultData.ResultDataSuccess(update(obj, w) ? "SUCCESS" : "FAIL");
    }

    @Override
    public void hasNew2280Record(List<TPdoDataL3Tcm2280> list) {
        //更新小时段产量记录
        currentHourOutput();
    }
}
